home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / lib / ruby / 1.8 / date.rb < prev    next >
Text File  |  2008-01-30  |  54KB  |  1,768 lines

  1. #
  2. # date.rb - date and time library
  3. #
  4. # Author: Tadayoshi Funaba 1998-2008
  5. #
  6. # Documentation: William Webber <william@williamwebber.com>
  7. #
  8. #--
  9. # $Id: date.rb,v 2.37 2008-01-17 20:16:31+09 tadf Exp $
  10. #++
  11. #
  12. # == Overview
  13. #
  14. # This file provides two classes for working with
  15. # dates and times.
  16. #
  17. # The first class, Date, represents dates.
  18. # It works with years, months, weeks, and days.
  19. # See the Date class documentation for more details.
  20. #
  21. # The second, DateTime, extends Date to include hours,
  22. # minutes, seconds, and fractions of a second.  It
  23. # provides basic support for time zones.  See the
  24. # DateTime class documentation for more details.
  25. #
  26. # === Ways of calculating the date.
  27. #
  28. # In common usage, the date is reckoned in years since or
  29. # before the Common Era (CE/BCE, also known as AD/BC), then
  30. # as a month and day-of-the-month within the current year.
  31. # This is known as the *Civil* *Date*, and abbreviated
  32. # as +civil+ in the Date class.
  33. #
  34. # Instead of year, month-of-the-year,  and day-of-the-month,
  35. # the date can also be reckoned in terms of year and
  36. # day-of-the-year.  This is known as the *Ordinal* *Date*,
  37. # and is abbreviated as +ordinal+ in the Date class.  (Note
  38. # that referring to this as the Julian date is incorrect.)
  39. #
  40. # The date can also be reckoned in terms of year, week-of-the-year,
  41. # and day-of-the-week.  This is known as the *Commercial*
  42. # *Date*, and is abbreviated as +commercial+ in the
  43. # Date class.  The commercial week runs Monday (day-of-the-week
  44. # 1) to Sunday (day-of-the-week 7), in contrast to the civil
  45. # week which runs Sunday (day-of-the-week 0) to Saturday
  46. # (day-of-the-week 6).  The first week of the commercial year
  47. # starts on the Monday on or before January 1, and the commercial
  48. # year itself starts on this Monday, not January 1.
  49. #
  50. # For scientific purposes, it is convenient to refer to a date
  51. # simply as a day count, counting from an arbitrary initial
  52. # day.  The date first chosen for this was January 1, 4713 BCE.
  53. # A count of days from this date is the *Julian* *Day* *Number*
  54. # or *Julian* *Date*, which is abbreviated as +jd+ in the
  55. # Date class.  This is in local time, and counts from midnight
  56. # on the initial day.  The stricter usage is in UTC, and counts
  57. # from midday on the initial day.  This is referred to in the
  58. # Date class as the *Astronomical* *Julian* *Day* *Number*, and
  59. # abbreviated as +ajd+.  In the Date class, the Astronomical
  60. # Julian Day Number includes fractional days.
  61. #
  62. # Another absolute day count is the *Modified* *Julian* *Day*
  63. # *Number*, which takes November 17, 1858 as its initial day.
  64. # This is abbreviated as +mjd+ in the Date class.  There
  65. # is also an *Astronomical* *Modified* *Julian* *Day* *Number*,
  66. # which is in UTC and includes fractional days.  This is
  67. # abbreviated as +amjd+ in the Date class.  Like the Modified
  68. # Julian Day Number (and unlike the Astronomical Julian
  69. # Day Number), it counts from midnight.
  70. #
  71. # Alternative calendars such as the Chinese Lunar Calendar,
  72. # the Islamic Calendar, or the French Revolutionary Calendar
  73. # are not supported by the Date class; nor are calendars that
  74. # are based on an Era different from the Common Era, such as
  75. # the Japanese Imperial Calendar or the Republic of China
  76. # Calendar.
  77. #
  78. # === Calendar Reform
  79. #
  80. # The standard civil year is 365 days long.  However, the
  81. # solar year is fractionally longer than this.  To account
  82. # for this, a *leap* *year* is occasionally inserted.  This
  83. # is a year with 366 days, the extra day falling on February 29.
  84. # In the early days of the civil calendar, every fourth
  85. # year without exception was a leap year.  This way of
  86. # reckoning leap years is the *Julian* *Calendar*.
  87. #
  88. # However, the solar year is marginally shorter than 365 1/4
  89. # days, and so the *Julian* *Calendar* gradually ran slow
  90. # over the centuries.  To correct this, every 100th year
  91. # (but not every 400th year) was excluded as a leap year.
  92. # This way of reckoning leap years, which we use today, is
  93. # the *Gregorian* *Calendar*.
  94. #
  95. # The Gregorian Calendar was introduced at different times
  96. # in different regions.  The day on which it was introduced
  97. # for a particular region is the *Day* *of* *Calendar*
  98. # *Reform* for that region.  This is abbreviated as +sg+
  99. # (for Start of Gregorian calendar) in the Date class.
  100. #
  101. # Two such days are of particular
  102. # significance.  The first is October 15, 1582, which was
  103. # the Day of Calendar Reform for Italy and most Catholic
  104. # countries.  The second is September 14, 1752, which was
  105. # the Day of Calendar Reform for England and its colonies
  106. # (including what is now the United States).  These two
  107. # dates are available as the constants Date::ITALY and
  108. # Date::ENGLAND, respectively.  (By comparison, Germany and
  109. # Holland, less Catholic than Italy but less stubborn than
  110. # England, changed over in 1698; Sweden in 1753; Russia not
  111. # till 1918, after the Revolution; and Greece in 1923.  Many
  112. # Orthodox churches still use the Julian Calendar.  A complete
  113. # list of Days of Calendar Reform can be found at
  114. # http://www.polysyllabic.com/GregConv.html.)
  115. #
  116. # Switching from the Julian to the Gregorian calendar
  117. # involved skipping a number of days to make up for the
  118. # accumulated lag, and the later the switch was (or is)
  119. # done, the more days need to be skipped.  So in 1582 in Italy,
  120. # 4th October was followed by 15th October, skipping 10 days; in 1752
  121. # in England, 2nd September was followed by 14th September, skipping
  122. # 11 days; and if I decided to switch from Julian to Gregorian
  123. # Calendar this midnight, I would go from 27th July 2003 (Julian)
  124. # today to 10th August 2003 (Gregorian) tomorrow, skipping
  125. # 13 days.  The Date class is aware of this gap, and a supposed
  126. # date that would fall in the middle of it is regarded as invalid.
  127. #
  128. # The Day of Calendar Reform is relevant to all date representations
  129. # involving years.  It is not relevant to the Julian Day Numbers,
  130. # except for converting between them and year-based representations.
  131. #
  132. # In the Date and DateTime classes, the Day of Calendar Reform or
  133. # +sg+ can be specified a number of ways.  First, it can be as
  134. # the Julian Day Number of the Day of Calendar Reform.  Second,
  135. # it can be using the constants Date::ITALY or Date::ENGLAND; these
  136. # are in fact the Julian Day Numbers of the Day of Calendar Reform
  137. # of the respective regions.  Third, it can be as the constant
  138. # Date::JULIAN, which means to always use the Julian Calendar.
  139. # Finally, it can be as the constant Date::GREGORIAN, which means
  140. # to always use the Gregorian Calendar.
  141. #
  142. # Note: in the Julian Calendar, New Years Day was March 25.  The
  143. # Date class does not follow this convention.
  144. #
  145. # === Time Zones
  146. #
  147. # DateTime objects support a simple representation
  148. # of time zones.  Time zones are represented as an offset
  149. # from UTC, as a fraction of a day.  This offset is the
  150. # how much local time is later (or earlier) than UTC.
  151. # UTC offset 0 is centred on England (also known as GMT).
  152. # As you travel east, the offset increases until you
  153. # reach the dateline in the middle of the Pacific Ocean;
  154. # as you travel west, the offset decreases.  This offset
  155. # is abbreviated as +of+ in the Date class.
  156. #
  157. # This simple representation of time zones does not take
  158. # into account the common practice of Daylight Savings
  159. # Time or Summer Time.
  160. #
  161. # Most DateTime methods return the date and the
  162. # time in local time.  The two exceptions are
  163. # #ajd() and #amjd(), which return the date and time
  164. # in UTC time, including fractional days.
  165. #
  166. # The Date class does not support time zone offsets, in that
  167. # there is no way to create a Date object with a time zone.
  168. # However, methods of the Date class when used by a
  169. # DateTime instance will use the time zone offset of this
  170. # instance.
  171. #
  172. # == Examples of use
  173. #
  174. # === Print out the date of every Sunday between two dates.
  175. #
  176. #     def print_sundays(d1, d2)
  177. #         d1 +=1 while (d1.wday != 0)
  178. #         d1.step(d2, 7) do |date|
  179. #             puts "#{Date::MONTHNAMES[date.mon]} #{date.day}"
  180. #         end
  181. #     end
  182. #
  183. #     print_sundays(Date::civil(2003, 4, 8), Date::civil(2003, 5, 23))
  184. #
  185. # === Calculate how many seconds to go till midnight on New Year's Day.
  186. #
  187. #     def secs_to_new_year(now = DateTime::now())
  188. #         new_year = DateTime.new(now.year + 1, 1, 1)
  189. #         dif = new_year - now
  190. #         hours, mins, secs, ignore_fractions = Date::day_fraction_to_time(dif)
  191. #         return hours * 60 * 60 + mins * 60 + secs
  192. #     end
  193. #
  194. #     puts secs_to_new_year()
  195.  
  196. require 'rational'
  197. require 'date/format'
  198.  
  199. # Class representing a date.
  200. #
  201. # See the documentation to the file date.rb for an overview.
  202. #
  203. # Internally, the date is represented as an Astronomical
  204. # Julian Day Number, +ajd+.  The Day of Calendar Reform, +sg+, is
  205. # also stored, for conversions to other date formats.  (There
  206. # is also an +of+ field for a time zone offset, but this
  207. # is only for the use of the DateTime subclass.)
  208. #
  209. # A new Date object is created using one of the object creation
  210. # class methods named after the corresponding date format, and the
  211. # arguments appropriate to that date format; for instance,
  212. # Date::civil() (aliased to Date::new()) with year, month,
  213. # and day-of-month, or Date::ordinal() with year and day-of-year.
  214. # All of these object creation class methods also take the
  215. # Day of Calendar Reform as an optional argument.
  216. #
  217. # Date objects are immutable once created.
  218. #
  219. # Once a Date has been created, date values
  220. # can be retrieved for the different date formats supported
  221. # using instance methods.  For instance, #mon() gives the
  222. # Civil month, #cwday() gives the Commercial day of the week,
  223. # and #yday() gives the Ordinal day of the year.  Date values
  224. # can be retrieved in any format, regardless of what format
  225. # was used to create the Date instance.
  226. #
  227. # The Date class includes the Comparable module, allowing
  228. # date objects to be compared and sorted, ranges of dates
  229. # to be created, and so forth.
  230. class Date
  231.  
  232.   include Comparable
  233.  
  234.   # Full month names, in English.  Months count from 1 to 12; a
  235.   # month's numerical representation indexed into this array
  236.   # gives the name of that month (hence the first element is nil).
  237.   MONTHNAMES = [nil] + %w(January February March April May June July
  238.               August September October November December)
  239.  
  240.   # Full names of days of the week, in English.  Days of the week
  241.   # count from 0 to 6 (except in the commercial week); a day's numerical
  242.   # representation indexed into this array gives the name of that day.
  243.   DAYNAMES = %w(Sunday Monday Tuesday Wednesday Thursday Friday Saturday)
  244.  
  245.   # Abbreviated month names, in English.
  246.   ABBR_MONTHNAMES = [nil] + %w(Jan Feb Mar Apr May Jun
  247.                    Jul Aug Sep Oct Nov Dec)
  248.  
  249.   # Abbreviated day names, in English.
  250.   ABBR_DAYNAMES = %w(Sun Mon Tue Wed Thu Fri Sat)
  251.  
  252.   [MONTHNAMES, DAYNAMES, ABBR_MONTHNAMES, ABBR_DAYNAMES].each do |xs|
  253.     xs.each{|x| x.freeze unless x.nil?}.freeze
  254.   end
  255.  
  256.   class Infinity < Numeric # :nodoc:
  257.  
  258.     include Comparable
  259.  
  260.     def initialize(d=1) @d = d <=> 0 end
  261.  
  262.     def d() @d end
  263.  
  264.     protected :d
  265.  
  266.     def zero? () false end
  267.     def finite? () false end
  268.     def infinite? () d.nonzero? end
  269.     def nan? () d.zero? end
  270.  
  271.     def abs() self.class.new end
  272.  
  273.     def -@ () self.class.new(-d) end
  274.     def +@ () self.class.new(+d) end
  275.  
  276.     def <=> (other)
  277.       case other
  278.       when Infinity; return d <=> other.d
  279.       when Numeric; return d
  280.       else
  281.     begin
  282.       l, r = other.coerce(self)
  283.       return l <=> r
  284.     rescue NoMethodError
  285.     end
  286.       end
  287.       nil
  288.     end
  289.  
  290.     def coerce(other)
  291.       case other
  292.       when Numeric; return -d, d
  293.       else
  294.     super
  295.       end
  296.     end
  297.  
  298.   end
  299.  
  300.   # The Julian Day Number of the Day of Calendar Reform for Italy
  301.   # and the Catholic countries.
  302.   ITALY     = 2299161 # 1582-10-15
  303.  
  304.   # The Julian Day Number of the Day of Calendar Reform for England
  305.   # and her Colonies.
  306.   ENGLAND   = 2361222 # 1752-09-14
  307.  
  308.   # A constant used to indicate that a Date should always use the
  309.   # Julian calendar.
  310.   JULIAN    =  Infinity.new
  311.  
  312.   # A constant used to indicate that a Date should always use the
  313.   # Gregorian calendar.
  314.   GREGORIAN = -Infinity.new
  315.  
  316.   HALF_DAYS_IN_DAY       = Rational(1, 2) # :nodoc:
  317.   HOURS_IN_DAY           = Rational(1, 24) # :nodoc:
  318.   MINUTES_IN_DAY         = Rational(1, 1440) # :nodoc:
  319.   SECONDS_IN_DAY         = Rational(1, 86400) # :nodoc:
  320.   MILLISECONDS_IN_DAY    = Rational(1, 86400*10**3) # :nodoc:
  321.   NANOSECONDS_IN_DAY     = Rational(1, 86400*10**9) # :nodoc:
  322.   MILLISECONDS_IN_SECOND = Rational(1, 10**3) # :nodoc:
  323.   NANOSECONDS_IN_SECOND  = Rational(1, 10**9) # :nodoc:
  324.  
  325.   MJD_EPOCH_IN_AJD       = Rational(4800001, 2) # 1858-11-17 # :nodoc:
  326.   UNIX_EPOCH_IN_AJD      = Rational(4881175, 2) # 1970-01-01 # :nodoc:
  327.   MJD_EPOCH_IN_CJD       = 2400001 # :nodoc:
  328.   UNIX_EPOCH_IN_CJD      = 2440588 # :nodoc:
  329.   LD_EPOCH_IN_CJD        = 2299160 # :nodoc:
  330.  
  331.   # Does a given Julian Day Number fall inside the old-style (Julian)
  332.   # calendar?
  333.   #
  334.   # +jd+ is the Julian Day Number in question. +sg+ may be Date::GREGORIAN,
  335.   # in which case the answer is false; it may be Date::JULIAN, in which case
  336.   # the answer is true; or it may a number representing the Day of
  337.   # Calendar Reform. Date::ENGLAND and Date::ITALY are two possible such
  338.   # days.
  339.  
  340.   def self.julian? (jd, sg)
  341.     case sg
  342.     when Numeric
  343.       jd < sg
  344.     else
  345.       if $VERBOSE
  346.     warn("#{caller.shift.sub(/:in .*/, '')}: " \
  347. "warning: do not use non-numerical object as julian day number anymore")
  348.       end
  349.       not sg
  350.     end
  351.   end
  352.  
  353.   # Does a given Julian Day Number fall inside the new-style (Gregorian)
  354.   # calendar?
  355.   #
  356.   # The reverse of self.os?  See the documentation for that method for
  357.   # more details.
  358.   def self.gregorian? (jd, sg) !julian?(jd, sg) end
  359.  
  360.   def self.fix_style(jd, sg) # :nodoc:
  361.     if julian?(jd, sg)
  362.     then JULIAN
  363.     else GREGORIAN end
  364.   end
  365.  
  366.   private_class_method :fix_style
  367.  
  368.   # Convert an Ordinal Date to a Julian Day Number.
  369.   #
  370.   # +y+ and +d+ are the year and day-of-year to convert.
  371.   # +sg+ specifies the Day of Calendar Reform.
  372.   #
  373.   # Returns the corresponding Julian Day Number.
  374.   def self.ordinal_to_jd(y, d, sg=GREGORIAN)
  375.     civil_to_jd(y, 1, d, sg)
  376.   end
  377.  
  378.   # Convert a Julian Day Number to an Ordinal Date.
  379.   #
  380.   # +jd+ is the Julian Day Number to convert.
  381.   # +sg+ specifies the Day of Calendar Reform.
  382.   #
  383.   # Returns the corresponding Ordinal Date as
  384.   # [year, day_of_year]
  385.   def self.jd_to_ordinal(jd, sg=GREGORIAN)
  386.     y = jd_to_civil(jd, sg)[0]
  387.     doy = jd - civil_to_jd(y - 1, 12, 31, fix_style(jd, sg))
  388.     return y, doy
  389.   end
  390.  
  391.   # Convert a Civil Date to a Julian Day Number.
  392.   # +y+, +m+, and +d+ are the year, month, and day of the
  393.   # month.  +sg+ specifies the Day of Calendar Reform.
  394.   #
  395.   # Returns the corresponding Julian Day Number.
  396.   def self.civil_to_jd(y, m, d, sg=GREGORIAN)
  397.     if m <= 2
  398.       y -= 1
  399.       m += 12
  400.     end
  401.     a = (y / 100.0).floor
  402.     b = 2 - a + (a / 4.0).floor
  403.     jd = (365.25 * (y + 4716)).floor +
  404.       (30.6001 * (m + 1)).floor +
  405.       d + b - 1524
  406.     if julian?(jd, sg)
  407.       jd -= b
  408.     end
  409.     jd
  410.   end
  411.  
  412.   # Convert a Julian Day Number to a Civil Date.  +jd+ is
  413.   # the Julian Day Number. +sg+ specifies the Day of
  414.   # Calendar Reform.
  415.   #
  416.   # Returns the corresponding [year, month, day_of_month]
  417.   # as a three-element array.
  418.   def self.jd_to_civil(jd, sg=GREGORIAN)
  419.     if julian?(jd, sg)
  420.       a = jd
  421.     else
  422.       x = ((jd - 1867216.25) / 36524.25).floor
  423.       a = jd + 1 + x - (x / 4.0).floor
  424.     end
  425.     b = a + 1524
  426.     c = ((b - 122.1) / 365.25).floor
  427.     d = (365.25 * c).floor
  428.     e = ((b - d) / 30.6001).floor
  429.     dom = b - d - (30.6001 * e).floor
  430.     if e <= 13
  431.       m = e - 1
  432.       y = c - 4716
  433.     else
  434.       m = e - 13
  435.       y = c - 4715
  436.     end
  437.     return y, m, dom
  438.   end
  439.  
  440.   # Convert a Commercial Date to a Julian Day Number.
  441.   #
  442.   # +y+, +w+, and +d+ are the (commercial) year, week of the year,
  443.   # and day of the week of the Commercial Date to convert.
  444.   # +sg+ specifies the Day of Calendar Reform.
  445.   def self.commercial_to_jd(y, w, d, ns=GREGORIAN)
  446.     jd = civil_to_jd(y, 1, 4, ns)
  447.     (jd - (((jd - 1) + 1) % 7)) +
  448.       7 * (w - 1) +
  449.       (d - 1)
  450.   end
  451.  
  452.   # Convert a Julian Day Number to a Commercial Date
  453.   #
  454.   # +jd+ is the Julian Day Number to convert.
  455.   # +sg+ specifies the Day of Calendar Reform.
  456.   #
  457.   # Returns the corresponding Commercial Date as
  458.   # [commercial_year, week_of_year, day_of_week]
  459.   def self.jd_to_commercial(jd, sg=GREGORIAN)
  460.     ns = fix_style(jd, sg)
  461.     a = jd_to_civil(jd - 3, ns)[0]
  462.     y = if jd >= commercial_to_jd(a + 1, 1, 1, ns) then a + 1 else a end
  463.     w = 1 + ((jd - commercial_to_jd(y, 1, 1, ns)) / 7).floor
  464.     d = (jd + 1) % 7
  465.     d = 7 if d == 0
  466.     return y, w, d
  467.   end
  468.  
  469.   def self.weeknum_to_jd(y, w, d, f=0, ns=GREGORIAN) # :nodoc:
  470.     a = civil_to_jd(y, 1, 1, ns) + 6
  471.     (a - ((a - f) + 1) % 7 - 7) + 7 * w + d
  472.   end
  473.  
  474.   def self.jd_to_weeknum(jd, f=0, sg=GREGORIAN) # :nodoc:
  475.     ns = fix_style(jd, sg)
  476.     y, m, d = jd_to_civil(jd, ns)
  477.     a = civil_to_jd(y, 1, 1, ns) + 6
  478.     w, d = (jd - (a - ((a - f) + 1) % 7) + 7).divmod(7)
  479.     return y, w, d
  480.   end
  481.  
  482.   private_class_method :weeknum_to_jd, :jd_to_weeknum
  483.  
  484.   # Convert an Astronomical Julian Day Number to a (civil) Julian
  485.   # Day Number.
  486.   #
  487.   # +ajd+ is the Astronomical Julian Day Number to convert.
  488.   # +of+ is the offset from UTC as a fraction of a day (defaults to 0).
  489.   #
  490.   # Returns the (civil) Julian Day Number as [day_number,
  491.   # fraction] where +fraction+ is always 1/2.
  492.   def self.ajd_to_jd(ajd, of=0) (ajd + of + HALF_DAYS_IN_DAY).divmod(1) end
  493.  
  494.   # Convert a (civil) Julian Day Number to an Astronomical Julian
  495.   # Day Number.
  496.   #
  497.   # +jd+ is the Julian Day Number to convert, and +fr+ is a
  498.   # fractional day.
  499.   # +of+ is the offset from UTC as a fraction of a day (defaults to 0).
  500.   #
  501.   # Returns the Astronomical Julian Day Number as a single
  502.   # numeric value.
  503.   def self.jd_to_ajd(jd, fr, of=0) jd + fr - of - HALF_DAYS_IN_DAY end
  504.  
  505.   # Convert a fractional day +fr+ to [hours, minutes, seconds,
  506.   # fraction_of_a_second]
  507.   def self.day_fraction_to_time(fr)
  508.     ss,  fr = fr.divmod(SECONDS_IN_DAY) # 4p
  509.     h,   ss = ss.divmod(3600)
  510.     min, s  = ss.divmod(60)
  511.     return h, min, s, fr
  512.   end
  513.  
  514.   # Convert an +h+ hour, +min+ minutes, +s+ seconds period
  515.   # to a fractional day.
  516.   begin
  517.     Rational(Rational(1, 2), 2) # a challenge
  518.  
  519.     def self.time_to_day_fraction(h, min, s)
  520.       Rational(h * 3600 + min * 60 + s, 86400) # 4p
  521.     end
  522.   rescue
  523.     def self.time_to_day_fraction(h, min, s)
  524.     if Integer === h && Integer === min && Integer === s
  525.       Rational(h * 3600 + min * 60 + s, 86400) # 4p
  526.     else
  527.       (h * 3600 + min * 60 + s).to_r/86400 # 4p
  528.     end
  529.     end
  530.   end
  531.  
  532.   # Convert an Astronomical Modified Julian Day Number to an
  533.   # Astronomical Julian Day Number.
  534.   def self.amjd_to_ajd(amjd) amjd + MJD_EPOCH_IN_AJD end
  535.  
  536.   # Convert an Astronomical Julian Day Number to an
  537.   # Astronomical Modified Julian Day Number.
  538.   def self.ajd_to_amjd(ajd) ajd - MJD_EPOCH_IN_AJD end
  539.  
  540.   # Convert a Modified Julian Day Number to a Julian
  541.   # Day Number.
  542.   def self.mjd_to_jd(mjd) mjd + MJD_EPOCH_IN_CJD end
  543.  
  544.   # Convert a Julian Day Number to a Modified Julian Day
  545.   # Number.
  546.   def self.jd_to_mjd(jd) jd - MJD_EPOCH_IN_CJD end
  547.  
  548.   # Convert a count of the number of days since the adoption
  549.   # of the Gregorian Calendar (in Italy) to a Julian Day Number.
  550.   def self.ld_to_jd(ld) ld + LD_EPOCH_IN_CJD end
  551.  
  552.   # Convert a Julian Day Number to the number of days since
  553.   # the adoption of the Gregorian Calendar (in Italy).
  554.   def self.jd_to_ld(jd) jd - LD_EPOCH_IN_CJD end
  555.  
  556.   # Convert a Julian Day Number to the day of the week.
  557.   #
  558.   # Sunday is day-of-week 0; Saturday is day-of-week 6.
  559.   def self.jd_to_wday(jd) (jd + 1) % 7 end
  560.  
  561.   # Is a year a leap year in the Julian calendar?
  562.   #
  563.   # All years divisible by 4 are leap years in the Julian calendar.
  564.   def self.julian_leap? (y) y % 4 == 0 end
  565.  
  566.   # Is a year a leap year in the Gregorian calendar?
  567.   #
  568.   # All years divisible by 4 are leap years in the Gregorian calendar,
  569.   # except for years divisible by 100 and not by 400.
  570.   def self.gregorian_leap? (y) y % 4 == 0 && y % 100 != 0 || y % 400 == 0 end
  571.  
  572.   class << self; alias_method :leap?, :gregorian_leap? end
  573.   class << self; alias_method :new!, :new end
  574.  
  575.   # Is +jd+ a valid Julian Day Number?
  576.   #
  577.   # If it is, returns it.  In fact, any value is treated as a valid
  578.   # Julian Day Number.
  579.   def self.valid_jd? (jd, sg=ITALY) jd end
  580.  
  581.   # Do the year +y+ and day-of-year +d+ make a valid Ordinal Date?
  582.   # Returns the corresponding Julian Day Number if they do, or
  583.   # nil if they don't.
  584.   #
  585.   # +d+ can be a negative number, in which case it counts backwards
  586.   # from the end of the year (-1 being the last day of the year).
  587.   # No year wraparound is performed, however, so valid values of
  588.   # +d+ are -365 .. -1, 1 .. 365 on a non-leap-year,
  589.   # -366 .. -1, 1 .. 366 on a leap year.
  590.   # A date falling in the period skipped in the Day of Calendar Reform
  591.   # adjustment is not valid.
  592.   #
  593.   # +sg+ specifies the Day of Calendar Reform.
  594.   def self.valid_ordinal? (y, d, sg=ITALY)
  595.     if d < 0
  596.       ny, = (y + 1).divmod(1)
  597.       jd = ordinal_to_jd(ny, d + 1, sg)
  598.       ns = fix_style(jd, sg)
  599.       return unless [y] == jd_to_ordinal(jd, sg)[0..0]
  600.       return unless [ny, 1] == jd_to_ordinal(jd - d, ns)
  601.     else
  602.       jd = ordinal_to_jd(y, d, sg)
  603.       return unless [y, d] == jd_to_ordinal(jd, sg)
  604.     end
  605.     jd
  606.   end
  607.  
  608.   # Do year +y+, month +m+, and day-of-month +d+ make a
  609.   # valid Civil Date?  Returns the corresponding Julian
  610.   # Day Number if they do, nil if they don't.
  611.   #
  612.   # +m+ and +d+ can be negative, in which case they count
  613.   # backwards from the end of the year and the end of the
  614.   # month respectively.  No wraparound is performed, however,
  615.   # and invalid values cause an ArgumentError to be raised.
  616.   # A date falling in the period skipped in the Day of Calendar
  617.   # Reform adjustment is not valid.
  618.   #
  619.   # +sg+ specifies the Day of Calendar Reform.
  620.   def self.valid_civil? (y, m, d, sg=ITALY)
  621.     if m < 0
  622.       m += 13
  623.     end
  624.     if d < 0
  625.       ny, nm = (y * 12 + m).divmod(12)
  626.       nm,    = (nm + 1).divmod(1)
  627.       jd = civil_to_jd(ny, nm, d + 1, sg)
  628.       ns = fix_style(jd, sg)
  629.       return unless [y, m] == jd_to_civil(jd, sg)[0..1]
  630.       return unless [ny, nm, 1] == jd_to_civil(jd - d, ns)
  631.     else
  632.       jd = civil_to_jd(y, m, d, sg)
  633.       return unless [y, m, d] == jd_to_civil(jd, sg)
  634.     end
  635.     jd
  636.   end
  637.  
  638.   class << self; alias_method :valid_date?, :valid_civil? end
  639.  
  640.   # Do year +y+, week-of-year +w+, and day-of-week +d+ make a
  641.   # valid Commercial Date?  Returns the corresponding Julian
  642.   # Day Number if they do, nil if they don't.
  643.   #
  644.   # Monday is day-of-week 1; Sunday is day-of-week 7.
  645.   #
  646.   # +w+ and +d+ can be negative, in which case they count
  647.   # backwards from the end of the year and the end of the
  648.   # week respectively.  No wraparound is performed, however,
  649.   # and invalid values cause an ArgumentError to be raised.
  650.   # A date falling in the period skipped in the Day of Calendar
  651.   # Reform adjustment is not valid.
  652.   #
  653.   # +sg+ specifies the Day of Calendar Reform.
  654.   def self.valid_commercial? (y, w, d, sg=ITALY)
  655.     if d < 0
  656.       d += 8
  657.     end
  658.     if w < 0
  659.       ny, nw, nd =
  660.     jd_to_commercial(commercial_to_jd(y + 1, 1, 1) + w * 7)
  661.       return unless ny == y
  662.       w = nw
  663.     end
  664.     jd = commercial_to_jd(y, w, d)
  665.     return unless gregorian?(jd, sg)
  666.     return unless [y, w, d] == jd_to_commercial(jd)
  667.     jd
  668.   end
  669.  
  670.   def self.valid_weeknum? (y, w, d, f, sg=ITALY) # :nodoc:
  671.     if d < 0
  672.       d += 7
  673.     end
  674.     if w < 0
  675.       ny, nw, nd, nf =
  676.     jd_to_weeknum(weeknum_to_jd(y + 1, 1, f, f) + w * 7, f)
  677.       return unless ny == y
  678.       w = nw
  679.     end
  680.     jd = weeknum_to_jd(y, w, d, f)
  681.     return unless gregorian?(jd, sg)
  682.     return unless [y, w, d] == jd_to_weeknum(jd, f)
  683.     jd
  684.   end
  685.  
  686.   private_class_method :valid_weeknum?
  687.  
  688.   # Do hour +h+, minute +min+, and second +s+ constitute a valid time?
  689.   #
  690.   # If they do, returns their value as a fraction of a day.  If not,
  691.   # returns nil.
  692.   #
  693.   # The 24-hour clock is used.  Negative values of +h+, +min+, and
  694.   # +sec+ are treating as counting backwards from the end of the
  695.   # next larger unit (e.g. a +min+ of -2 is treated as 58).  No
  696.   # wraparound is performed.
  697.   def self.valid_time? (h, min, s)
  698.     h   += 24 if h   < 0
  699.     min += 60 if min < 0
  700.     s   += 60 if s   < 0
  701.     return unless ((0...24) === h &&
  702.            (0...60) === min &&
  703.            (0...60) === s) ||
  704.           (24 == h &&
  705.             0 == min &&
  706.             0 == s)
  707.     time_to_day_fraction(h, min, s)
  708.   end
  709.  
  710.   # Create a new Date object from a Julian Day Number.
  711.   #
  712.   # +jd+ is the Julian Day Number; if not specified, it defaults to
  713.   # 0.
  714.   # +sg+ specifies the Day of Calendar Reform.
  715.   def self.jd(jd=0, sg=ITALY)
  716.     jd = valid_jd?(jd, sg)
  717.     new!(jd_to_ajd(jd, 0, 0), 0, sg)
  718.   end
  719.  
  720.   # Create a new Date object from an Ordinal Date, specified
  721.   # by year +y+ and day-of-year +d+. +d+ can be negative,
  722.   # in which it counts backwards from the end of the year.
  723.   # No year wraparound is performed, however.  An invalid
  724.   # value for +d+ results in an ArgumentError being raised.
  725.   #
  726.   # +y+ defaults to -4712, and +d+ to 1; this is Julian Day
  727.   # Number day 0.
  728.   #
  729.   # +sg+ specifies the Day of Calendar Reform.
  730.   def self.ordinal(y=-4712, d=1, sg=ITALY)
  731.     unless jd = valid_ordinal?(y, d, sg)
  732.       raise ArgumentError, 'invalid date'
  733.     end
  734.     new!(jd_to_ajd(jd, 0, 0), 0, sg)
  735.   end
  736.  
  737.   # Create a new Date object for the Civil Date specified by
  738.   # year +y+, month +m+, and day-of-month +d+.
  739.   #
  740.   # +m+ and +d+ can be negative, in which case they count
  741.   # backwards from the end of the year and the end of the
  742.   # month respectively.  No wraparound is performed, however,
  743.   # and invalid values cause an ArgumentError to be raised.
  744.   # can be negative
  745.   #
  746.   # +y+ defaults to -4712, +m+ to 1, and +d+ to 1; this is
  747.   # Julian Day Number day 0.
  748.   #
  749.   # +sg+ specifies the Day of Calendar Reform.
  750.   def self.civil(y=-4712, m=1, d=1, sg=ITALY)
  751.     unless jd = valid_civil?(y, m, d, sg)
  752.       raise ArgumentError, 'invalid date'
  753.     end
  754.     new!(jd_to_ajd(jd, 0, 0), 0, sg)
  755.   end
  756.  
  757.   class << self; alias_method :new, :civil end
  758.  
  759.   # Create a new Date object for the Commercial Date specified by
  760.   # year +y+, week-of-year +w+, and day-of-week +d+.
  761.   #
  762.   # Monday is day-of-week 1; Sunday is day-of-week 7.
  763.   #
  764.   # +w+ and +d+ can be negative, in which case they count
  765.   # backwards from the end of the year and the end of the
  766.   # week respectively.  No wraparound is performed, however,
  767.   # and invalid values cause an ArgumentError to be raised.
  768.   #
  769.   # +y+ defaults to 1582, +w+ to 41, and +d+ to 5, the Day of
  770.   # Calendar Reform for Italy and the Catholic countries.
  771.   #
  772.   # +sg+ specifies the Day of Calendar Reform.
  773.   def self.commercial(y=1582, w=41, d=5, sg=ITALY)
  774.     unless jd = valid_commercial?(y, w, d, sg)
  775.       raise ArgumentError, 'invalid date'
  776.     end
  777.     new!(jd_to_ajd(jd, 0, 0), 0, sg)
  778.   end
  779.  
  780.   def self.weeknum(y=1582, w=41, d=5, f=0, sg=ITALY) # :nodoc:
  781.     unless jd = valid_weeknum?(y, w, d, f, sg)
  782.       raise ArgumentError, 'invalid date'
  783.     end
  784.     new!(jd_to_ajd(jd, 0, 0), 0, sg)
  785.   end
  786.  
  787.   private_class_method :weeknum
  788.  
  789.   def self.rewrite_frags(elem) # :nodoc:
  790.     elem ||= {}
  791.     if seconds = elem[:seconds]
  792.       d,   fr = seconds.divmod(86400)
  793.       h,   fr = fr.divmod(3600)
  794.       min, fr = fr.divmod(60)
  795.       s,   fr = fr.divmod(1)
  796.       elem[:jd] = UNIX_EPOCH_IN_CJD + d
  797.       elem[:hour] = h
  798.       elem[:min] = min
  799.       elem[:sec] = s
  800.       elem[:sec_fraction] = fr
  801.       elem.delete(:seconds)
  802.       elem.delete(:offset)
  803.     end
  804.     elem
  805.   end
  806.  
  807.   private_class_method :rewrite_frags
  808.  
  809.   def self.complete_frags(elem) # :nodoc:
  810.     i = 0
  811.     g = [[:time, [:hour, :min, :sec]],
  812.      [nil, [:jd]],
  813.      [:ordinal, [:year, :yday, :hour, :min, :sec]],
  814.      [:civil, [:year, :mon, :mday, :hour, :min, :sec]],
  815.      [:commercial, [:cwyear, :cweek, :cwday, :hour, :min, :sec]],
  816.      [:wday, [:wday, :hour, :min, :sec]],
  817.      [:wnum0, [:year, :wnum0, :wday, :hour, :min, :sec]],
  818.      [:wnum1, [:year, :wnum1, :wday, :hour, :min, :sec]],
  819.      [nil, [:cwyear, :cweek, :wday, :hour, :min, :sec]],
  820.      [nil, [:year, :wnum0, :cwday, :hour, :min, :sec]],
  821.      [nil, [:year, :wnum1, :cwday, :hour, :min, :sec]]].
  822.       collect{|k, a| e = elem.values_at(*a).compact; [k, a, e]}.
  823.       select{|k, a, e| e.size > 0}.
  824.       sort_by{|k, a, e| [e.size, i -= 1]}.last
  825.  
  826.     d = nil
  827.  
  828.     if g && g[0] && (g[1].size - g[2].size) != 0
  829.       d ||= Date.today
  830.  
  831.       case g[0]
  832.       when :ordinal
  833.     elem[:year] ||= d.year
  834.     elem[:yday] ||= 1
  835.       when :civil
  836.     g[1].each do |e|
  837.       break if elem[e]
  838.       elem[e] = d.__send__(e)
  839.     end
  840.     elem[:mon]  ||= 1
  841.     elem[:mday] ||= 1
  842.       when :commercial
  843.     g[1].each do |e|
  844.       break if elem[e]
  845.       elem[e] = d.__send__(e)
  846.     end
  847.     elem[:cweek] ||= 1
  848.     elem[:cwday] ||= 1
  849.       when :wday
  850.     elem[:jd] ||= (d - d.wday + elem[:wday]).jd
  851.       when :wnum0
  852.     g[1].each do |e|
  853.       break if elem[e]
  854.       elem[e] = d.__send__(e)
  855.     end
  856.     elem[:wnum0] ||= 0
  857.     elem[:wday]  ||= 0
  858.       when :wnum1
  859.     g[1].each do |e|
  860.       break if elem[e]
  861.       elem[e] = d.__send__(e)
  862.     end
  863.     elem[:wnum1] ||= 0
  864.     elem[:wday]  ||= 0
  865.       end
  866.     end
  867.  
  868.     if g && g[0] == :time
  869.       if self <= DateTime
  870.     d ||= Date.today
  871.     elem[:jd] ||= d.jd
  872.       end
  873.     end
  874.  
  875.     elem[:hour] ||= 0
  876.     elem[:min]  ||= 0
  877.     elem[:sec]  ||= 0
  878.     elem[:sec] = [elem[:sec], 59].min
  879.  
  880.     elem
  881.   end
  882.  
  883.   private_class_method :complete_frags
  884.  
  885.   def self.valid_date_frags?(elem, sg) # :nodoc:
  886.     catch :jd do
  887.       a = elem.values_at(:jd)
  888.       if a.all?
  889.     if jd = valid_jd?(*(a << sg))
  890.       throw :jd, jd
  891.     end
  892.       end
  893.  
  894.       a = elem.values_at(:year, :yday)
  895.       if a.all?
  896.     if jd = valid_ordinal?(*(a << sg))
  897.       throw :jd, jd
  898.     end
  899.       end
  900.  
  901.       a = elem.values_at(:year, :mon, :mday)
  902.       if a.all?
  903.     if jd = valid_civil?(*(a << sg))
  904.       throw :jd, jd
  905.     end
  906.       end
  907.  
  908.       a = elem.values_at(:cwyear, :cweek, :cwday)
  909.       if a[2].nil? && elem[:wday]
  910.     a[2] = elem[:wday].nonzero? || 7
  911.       end
  912.       if a.all?
  913.     if jd = valid_commercial?(*(a << sg))
  914.       throw :jd, jd
  915.     end
  916.       end
  917.  
  918.       a = elem.values_at(:year, :wnum0, :wday)
  919.       if a[2].nil? && elem[:cwday]
  920.     a[2] = elem[:cwday] % 7
  921.       end
  922.       if a.all?
  923.     if jd = valid_weeknum?(*(a << 0 << sg))
  924.       throw :jd, jd
  925.     end
  926.       end
  927.  
  928.       a = elem.values_at(:year, :wnum1, :wday)
  929.       if a[2]
  930.     a[2] = (a[2] - 1) % 7
  931.       end
  932.       if a[2].nil? && elem[:cwday]
  933.     a[2] = (elem[:cwday] - 1) % 7
  934.       end
  935.       if a.all?
  936.     if jd = valid_weeknum?(*(a << 1 << sg))
  937.       throw :jd, jd
  938.     end
  939.       end
  940.     end
  941.   end
  942.  
  943.   private_class_method :valid_date_frags?
  944.  
  945.   def self.valid_time_frags? (elem) # :nodoc:
  946.     h, min, s = elem.values_at(:hour, :min, :sec)
  947.     valid_time?(h, min, s)
  948.   end
  949.  
  950.   private_class_method :valid_time_frags?
  951.  
  952.   def self.new_by_frags(elem, sg) # :nodoc:
  953.     elem = rewrite_frags(elem)
  954.     elem = complete_frags(elem)
  955.     unless jd = valid_date_frags?(elem, sg)
  956.       raise ArgumentError, 'invalid date'
  957.     end
  958.     new!(jd_to_ajd(jd, 0, 0), 0, sg)
  959.   end
  960.  
  961.   private_class_method :new_by_frags
  962.  
  963.   # Create a new Date object by parsing from a String
  964.   # according to a specified format.
  965.   #
  966.   # +str+ is a String holding a date representation.
  967.   # +fmt+ is the format that the date is in.  See
  968.   # date/format.rb for details on supported formats.
  969.   #
  970.   # The default +str+ is '-4712-01-01', and the default
  971.   # +fmt+ is '%F', which means Year-Month-Day_of_Month.
  972.   # This gives Julian Day Number day 0.
  973.   #
  974.   # +sg+ specifies the Day of Calendar Reform.
  975.   #
  976.   # An ArgumentError will be raised if +str+ cannot be
  977.   # parsed.
  978.   def self.strptime(str='-4712-01-01', fmt='%F', sg=ITALY)
  979.     elem = _strptime(str, fmt)
  980.     new_by_frags(elem, sg)
  981.   end
  982.  
  983.   # Create a new Date object by parsing from a String,
  984.   # without specifying the format.
  985.   #
  986.   # +str+ is a String holding a date representation.
  987.   # +comp+ specifies whether to interpret 2-digit years
  988.   # as 19XX (>= 69) or 20XX (< 69); the default is not to.
  989.   # The method will attempt to parse a date from the String
  990.   # using various heuristics; see #_parse in date/format.rb
  991.   # for more details.  If parsing fails, an ArgumentError
  992.   # will be raised.
  993.   #
  994.   # The default +str+ is '-4712-01-01'; this is Julian
  995.   # Day Number day 0.
  996.   #
  997.   # +sg+ specifies the Day of Calendar Reform.
  998.   def self.parse(str='-4712-01-01', comp=false, sg=ITALY)
  999.     elem = _parse(str, comp)
  1000.     new_by_frags(elem, sg)
  1001.   end
  1002.  
  1003.   class << self
  1004.  
  1005.     def once(*ids) # :nodoc:
  1006.       for id in ids
  1007.     module_eval <<-"end;"
  1008.       alias_method :__#{id.to_i}__, :#{id.to_s}
  1009.       private :__#{id.to_i}__
  1010.       def #{id.to_s}(*args, &block)
  1011.         (@__#{id.to_i}__ ||= [__#{id.to_i}__(*args, &block)])[0]
  1012.       end
  1013.     end;
  1014.       end
  1015.     end
  1016.  
  1017.     private :once
  1018.  
  1019.   end
  1020.  
  1021.   # *NOTE* this is the documentation for the method new!().  If
  1022.   # you are reading this as the documentation for new(), that is
  1023.   # because rdoc doesn't fully support the aliasing of the
  1024.   # initialize() method.
  1025.   # new() is in
  1026.   # fact an alias for #civil(): read the documentation for that
  1027.   # method instead.
  1028.   #
  1029.   # Create a new Date object.
  1030.   #
  1031.   # +ajd+ is the Astronomical Julian Day Number.
  1032.   # +of+ is the offset from UTC as a fraction of a day.
  1033.   # Both default to 0.
  1034.   #
  1035.   # +sg+ specifies the Day of Calendar Reform to use for this
  1036.   # Date object.
  1037.   #
  1038.   # Using one of the factory methods such as Date::civil is
  1039.   # generally easier and safer.
  1040.   def initialize(ajd=0, of=0, sg=ITALY) @ajd, @of, @sg = ajd, of, sg end
  1041.  
  1042.   # Get the date as an Astronomical Julian Day Number.
  1043.   def ajd() @ajd end
  1044.  
  1045.   # Get the date as an Astronomical Modified Julian Day Number.
  1046.   def amjd() self.class.ajd_to_amjd(@ajd) end
  1047.  
  1048.   once :amjd
  1049.  
  1050.   # Get the date as a Julian Day Number.
  1051.   def jd() self.class.ajd_to_jd(@ajd, @of)[0] end
  1052.  
  1053.   # Get any fractional day part of the date.
  1054.   def day_fraction() self.class.ajd_to_jd(@ajd, @of)[1] end
  1055.  
  1056.   # Get the date as a Modified Julian Day Number.
  1057.   def mjd() self.class.jd_to_mjd(jd) end
  1058.  
  1059.   # Get the date as the number of days since the Day of Calendar
  1060.   # Reform (in Italy and the Catholic countries).
  1061.   def ld() self.class.jd_to_ld(jd) end
  1062.  
  1063.   once :jd, :day_fraction, :mjd, :ld
  1064.  
  1065.   # Get the date as a Civil Date, [year, month, day_of_month]
  1066.   def civil() self.class.jd_to_civil(jd, @sg) end # :nodoc:
  1067.  
  1068.   # Get the date as an Ordinal Date, [year, day_of_year]
  1069.   def ordinal() self.class.jd_to_ordinal(jd, @sg) end # :nodoc:
  1070.  
  1071.   # Get the date as a Commercial Date, [year, week_of_year, day_of_week]
  1072.   def commercial() self.class.jd_to_commercial(jd, @sg) end # :nodoc:
  1073.  
  1074.   def weeknum0() self.class.__send__(:jd_to_weeknum, jd, 0, @sg) end # :nodoc:
  1075.   def weeknum1() self.class.__send__(:jd_to_weeknum, jd, 1, @sg) end # :nodoc:
  1076.  
  1077.   once :civil, :ordinal, :commercial, :weeknum0, :weeknum1
  1078.   private :civil, :ordinal, :commercial, :weeknum0, :weeknum1
  1079.  
  1080.   # Get the year of this date.
  1081.   def year() civil[0] end
  1082.  
  1083.   # Get the day-of-the-year of this date.
  1084.   #
  1085.   # January 1 is day-of-the-year 1
  1086.   def yday() ordinal[1] end
  1087.  
  1088.   # Get the month of this date.
  1089.   #
  1090.   # January is month 1.
  1091.   def mon() civil[1] end
  1092.  
  1093.   # Get the day-of-the-month of this date.
  1094.   def mday() civil[2] end
  1095.  
  1096.   alias_method :month, :mon
  1097.   alias_method :day, :mday
  1098.  
  1099.   def wnum0() weeknum0[1] end # :nodoc:
  1100.   def wnum1() weeknum1[1] end # :nodoc:
  1101.  
  1102.   private :wnum0, :wnum1
  1103.  
  1104.   # Get the time of this date as [hours, minutes, seconds,
  1105.   # fraction_of_a_second]
  1106.   def time() self.class.day_fraction_to_time(day_fraction) end # :nodoc:
  1107.  
  1108.   once :time
  1109.   private :time
  1110.  
  1111.   # Get the hour of this date.
  1112.   def hour() time[0] end
  1113.  
  1114.   # Get the minute of this date.
  1115.   def min() time[1] end
  1116.  
  1117.   # Get the second of this date.
  1118.   def sec() time[2] end
  1119.  
  1120.   # Get the fraction-of-a-second of this date.  The unit is in days.
  1121.   # I do NOT recommend you to use this method.
  1122.   def sec_fraction() time[3] end
  1123.  
  1124. =begin
  1125.   alias_method :minute, :min
  1126.   alias_method :second, :sec
  1127.   alias_method :second_fraction, :sec_fraction
  1128. =end
  1129.  
  1130.   private :hour, :min, :sec, :sec_fraction
  1131. #      :minute, :second, :second_fraction
  1132.  
  1133.   def zone() strftime('%:z') end
  1134.  
  1135.   private :zone
  1136.  
  1137.   # Get the commercial year of this date.  See *Commercial* *Date*
  1138.   # in the introduction for how this differs from the normal year.
  1139.   def cwyear() commercial[0] end
  1140.  
  1141.   # Get the commercial week of the year of this date.
  1142.   def cweek() commercial[1] end
  1143.  
  1144.   # Get the commercial day of the week of this date.  Monday is
  1145.   # commercial day-of-week 1; Sunday is commercial day-of-week 7.
  1146.   def cwday() commercial[2] end
  1147.  
  1148.   # Get the week day of this date.  Sunday is day-of-week 0;
  1149.   # Saturday is day-of-week 6.
  1150.   def wday() self.class.jd_to_wday(jd) end
  1151.  
  1152.   once :wday
  1153.  
  1154. =begin
  1155.   MONTHNAMES.each_with_index do |n, i|
  1156.     if n
  1157.       define_method(n.downcase + '?'){mon == i}
  1158.     end
  1159.   end
  1160.  
  1161.   DAYNAMES.each_with_index do |n, i|
  1162.     define_method(n.downcase + '?'){wday == i}
  1163.   end
  1164. =end
  1165.  
  1166.   # Is the current date old-style (Julian Calendar)?
  1167.   def julian? () self.class.julian?(jd, @sg) end
  1168.  
  1169.   # Is the current date new-style (Gregorian Calendar)?
  1170.   def gregorian? () self.class.gregorian?(jd, @sg) end
  1171.  
  1172.   once :julian?, :gregorian?
  1173.  
  1174.   def fix_style # :nodoc:
  1175.     if julian?
  1176.     then self.class::JULIAN
  1177.     else self.class::GREGORIAN end
  1178.   end
  1179.  
  1180.   private :fix_style
  1181.  
  1182.   # Is this a leap year?
  1183.   def leap?
  1184.     self.class.jd_to_civil(self.class.civil_to_jd(year, 3, 1, fix_style) - 1,
  1185.              fix_style)[-1] == 29
  1186.   end
  1187.  
  1188.   once :leap?
  1189.  
  1190.   # When is the Day of Calendar Reform for this Date object?
  1191.   def start() @sg end
  1192.  
  1193.   # Create a copy of this Date object using a new Day of Calendar Reform.
  1194.   def new_start(sg=self.class::ITALY) self.class.new!(@ajd, @of, sg) end
  1195.  
  1196.   # Create a copy of this Date object that uses the Italian/Catholic
  1197.   # Day of Calendar Reform.
  1198.   def italy() new_start(self.class::ITALY) end
  1199.  
  1200.   # Create a copy of this Date object that uses the English/Colonial
  1201.   # Day of Calendar Reform.
  1202.   def england() new_start(self.class::ENGLAND) end
  1203.  
  1204.   # Create a copy of this Date object that always uses the Julian
  1205.   # Calendar.
  1206.   def julian() new_start(self.class::JULIAN) end
  1207.  
  1208.   # Create a copy of this Date object that always uses the Gregorian
  1209.   # Calendar.
  1210.   def gregorian() new_start(self.class::GREGORIAN) end
  1211.  
  1212.   def offset() @of end
  1213.  
  1214.   def new_offset(of=0)
  1215.     if String === of
  1216.       of = Rational(zone_to_diff(of) || 0, 86400)
  1217.     end
  1218.     self.class.new!(@ajd, of, @sg)
  1219.   end
  1220.  
  1221.   private :offset, :new_offset
  1222.  
  1223.   # Return a new Date object that is +n+ days later than the
  1224.   # current one.
  1225.   #
  1226.   # +n+ may be a negative value, in which case the new Date
  1227.   # is earlier than the current one; however, #-() might be
  1228.   # more intuitive.
  1229.   #
  1230.   # If +n+ is not a Numeric, a TypeError will be thrown.  In
  1231.   # particular, two Dates cannot be added to each other.
  1232.   def + (n)
  1233.     case n
  1234.     when Numeric; return self.class.new!(@ajd + n, @of, @sg)
  1235.     end
  1236.     raise TypeError, 'expected numeric'
  1237.   end
  1238.  
  1239.   # If +x+ is a Numeric value, create a new Date object that is
  1240.   # +x+ days earlier than the current one.
  1241.   #
  1242.   # If +x+ is a Date, return the number of days between the
  1243.   # two dates; or, more precisely, how many days later the current
  1244.   # date is than +x+.
  1245.   #
  1246.   # If +x+ is neither Numeric nor a Date, a TypeError is raised.
  1247.   def - (x)
  1248.     case x
  1249.     when Numeric; return self.class.new!(@ajd - x, @of, @sg)
  1250.     when Date;    return @ajd - x.ajd
  1251.     end
  1252.     raise TypeError, 'expected numeric or date'
  1253.   end
  1254.  
  1255.   # Compare this date with another date.
  1256.   #
  1257.   # +other+ can also be a Numeric value, in which case it is
  1258.   # interpreted as an Astronomical Julian Day Number.
  1259.   #
  1260.   # Comparison is by Astronomical Julian Day Number, including
  1261.   # fractional days.  This means that both the time and the
  1262.   # timezone offset are taken into account when comparing
  1263.   # two DateTime instances.  When comparing a DateTime instance
  1264.   # with a Date instance, the time of the latter will be
  1265.   # considered as falling on midnight UTC.
  1266.   def <=> (other)
  1267.     case other
  1268.     when Numeric; return @ajd <=> other
  1269.     when Date;    return @ajd <=> other.ajd
  1270.     end
  1271.     nil
  1272.   end
  1273.  
  1274.   # The relationship operator for Date.
  1275.   #
  1276.   # Compares dates by Julian Day Number.  When comparing
  1277.   # two DateTime instances, or a DateTime with a Date,
  1278.   # the instances will be regarded as equivalent if they
  1279.   # fall on the same date in local time.
  1280.   def === (other)
  1281.     case other
  1282.     when Numeric; return jd == other
  1283.     when Date;    return jd == other.jd
  1284.     end
  1285.     false
  1286.   end
  1287.  
  1288.   def next_day(n=1) self + n end
  1289. # def prev_day(n=1) self - n end
  1290.  
  1291.   private :next_day
  1292.  
  1293.   # Return a new Date one day after this one.
  1294.   def next() next_day end
  1295.  
  1296.   alias_method :succ, :next
  1297.  
  1298.   # Return a new Date object that is +n+ months later than
  1299.   # the current one.
  1300.   #
  1301.   # If the day-of-the-month of the current Date is greater
  1302.   # than the last day of the target month, the day-of-the-month
  1303.   # of the returned Date will be the last day of the target month.
  1304.   def >> (n)
  1305.     y, m = (year * 12 + (mon - 1) + n).divmod(12)
  1306.     m,   = (m + 1)                    .divmod(1)
  1307.     d = mday
  1308.     d -= 1 until jd2 = self.class.valid_civil?(y, m, d, fix_style)
  1309.     self + (jd2 - jd)
  1310.   end
  1311.  
  1312.   # Return a new Date object that is +n+ months earlier than
  1313.   # the current one.
  1314.   #
  1315.   # If the day-of-the-month of the current Date is greater
  1316.   # than the last day of the target month, the day-of-the-month
  1317.   # of the returned Date will be the last day of the target month.
  1318.   def << (n) self >> -n end
  1319.  
  1320. =begin
  1321.   def next_month(n=1) self >> n end
  1322.   def prev_month(n=1) self << n end
  1323.  
  1324.   def next_year(n=1) self >> n * 12 end
  1325.   def prev_year(n=1) self << n * 12 end
  1326. =end
  1327.  
  1328. #  require 'enumerator'
  1329.  
  1330.   # Step the current date forward +step+ days at a
  1331.   # time (or backward, if +step+ is negative) until
  1332.   # we reach +limit+ (inclusive), yielding the resultant
  1333.   # date at each step.
  1334.   def step(limit, step=1) # :yield: date
  1335. =begin
  1336.     if step.zero?
  1337.       raise ArgumentError, "step can't be 0"
  1338.     end
  1339. =end
  1340. =begin
  1341.     unless block_given?
  1342.       return to_enum(:step, limit, step)
  1343.     end
  1344. =end
  1345.     da = self
  1346.     op = %w(- <= >=)[step <=> 0]
  1347.     while da.__send__(op, limit)
  1348.       yield da
  1349.       da += step
  1350.     end
  1351.     self
  1352.   end
  1353.  
  1354.   # Step forward one day at a time until we reach +max+
  1355.   # (inclusive), yielding each date as we go.
  1356.   def upto(max, &block) # :yield: date
  1357.     step(max, +1, &block)
  1358.   end
  1359.  
  1360.   # Step backward one day at a time until we reach +min+
  1361.   # (inclusive), yielding each date as we go.
  1362.   def downto(min, &block) # :yield: date
  1363.     step(min, -1, &block)
  1364.   end
  1365.  
  1366.   # Is this Date equal to +other+?
  1367.   #
  1368.   # +other+ must both be a Date object, and represent the same date.
  1369.   def eql? (other) Date === other && self == other end
  1370.  
  1371.   # Calculate a hash value for this date.
  1372.   def hash() @ajd.hash end
  1373.  
  1374.   # Return internal object state as a programmer-readable string.
  1375.   def inspect() format('#<%s: %s,%s,%s>', self.class, @ajd, @of, @sg) end
  1376.  
  1377.   # Return the date as a human-readable string.
  1378.   #
  1379.   # The format used is YYYY-MM-DD.
  1380.   def to_s() format('%.4d-%02d-%02d', year, mon, mday) end # 4p
  1381.  
  1382.   # Dump to Marshal format.
  1383.   def _dump(limit) Marshal.dump([@ajd, @of, @sg], -1) end
  1384.  
  1385. # def self._load(str) new!(*Marshal.load(str)) end
  1386.  
  1387.   # Load from Marshal format.
  1388.   def self._load(str)
  1389.     a = Marshal.load(str)
  1390.     if a.size == 2
  1391.       ajd,     sg = a
  1392.            of = 0
  1393.       ajd -= 1.to_r/2
  1394.     else
  1395.       ajd, of, sg = a
  1396.     end
  1397.     new!(ajd, of, sg)
  1398.   end
  1399.  
  1400. end
  1401.  
  1402. # Class representing a date and time.
  1403. #
  1404. # See the documentation to the file date.rb for an overview.
  1405. #
  1406. # DateTime objects are immutable once created.
  1407. #
  1408. # == Other methods.
  1409. #
  1410. # The following methods are defined in Date, but declared private
  1411. # there.  They are made public in DateTime.  They are documented
  1412. # here.
  1413. #
  1414. # === hour()
  1415. #
  1416. # Get the hour-of-the-day of the time.  This is given
  1417. # using the 24-hour clock, counting from midnight.  The first
  1418. # hour after midnight is hour 0; the last hour of the day is
  1419. # hour 23.
  1420. #
  1421. # === min()
  1422. #
  1423. # Get the minute-of-the-hour of the time.
  1424. #
  1425. # === sec()
  1426. #
  1427. # Get the second-of-the-minute of the time.
  1428. #
  1429. # === sec_fraction()
  1430. #
  1431. # Get the fraction of a second of the time.  This is returned as
  1432. # a +Rational+.  The unit is in days.
  1433. # I do NOT recommend you to use this method.
  1434. #
  1435. # === zone()
  1436. #
  1437. # Get the time zone as a String.  This is representation of the
  1438. # time offset such as "+1000", not the true time-zone name.
  1439. #
  1440. # === offset()
  1441. #
  1442. # Get the time zone offset as a fraction of a day.  This is returned
  1443. # as a +Rational+.
  1444. #
  1445. # === new_offset(of=0)
  1446. #
  1447. # Create a new DateTime object, identical to the current one, except
  1448. # with a new time zone offset of +of+.  +of+ is the new offset from
  1449. # UTC as a fraction of a day.
  1450. #
  1451. class DateTime < Date
  1452.  
  1453.   # Create a new DateTime object corresponding to the specified
  1454.   # Julian Day Number +jd+ and hour +h+, minute +min+, second +s+.
  1455.   #
  1456.   # The 24-hour clock is used.  Negative values of +h+, +min+, and
  1457.   # +sec+ are treating as counting backwards from the end of the
  1458.   # next larger unit (e.g. a +min+ of -2 is treated as 58).  No
  1459.   # wraparound is performed.  If an invalid time portion is specified,
  1460.   # an ArgumentError is raised.
  1461.   #
  1462.   # +of+ is the offset from UTC as a fraction of a day (defaults to 0).
  1463.   # +sg+ specifies the Day of Calendar Reform.
  1464.   #
  1465.   # All day/time values default to 0.
  1466.   def self.jd(jd=0, h=0, min=0, s=0, of=0, sg=ITALY)
  1467.     unless (jd = valid_jd?(jd, sg)) &&
  1468.        (fr = valid_time?(h, min, s))
  1469.       raise ArgumentError, 'invalid date'
  1470.     end
  1471.     if String === of
  1472.       of = Rational(zone_to_diff(of) || 0, 86400)
  1473.     end
  1474.     new!(jd_to_ajd(jd, fr, of), of, sg)
  1475.   end
  1476.  
  1477.   # Create a new DateTime object corresponding to the specified
  1478.   # Ordinal Date and hour +h+, minute +min+, second +s+.
  1479.   #
  1480.   # The 24-hour clock is used.  Negative values of +h+, +min+, and
  1481.   # +sec+ are treating as counting backwards from the end of the
  1482.   # next larger unit (e.g. a +min+ of -2 is treated as 58).  No
  1483.   # wraparound is performed.  If an invalid time portion is specified,
  1484.   # an ArgumentError is raised.
  1485.   #
  1486.   # +of+ is the offset from UTC as a fraction of a day (defaults to 0).
  1487.   # +sg+ specifies the Day of Calendar Reform.
  1488.   #
  1489.   # +y+ defaults to -4712, and +d+ to 1; this is Julian Day Number
  1490.   # day 0.  The time values default to 0.
  1491.   def self.ordinal(y=-4712, d=1, h=0, min=0, s=0, of=0, sg=ITALY)
  1492.     unless (jd = valid_ordinal?(y, d, sg)) &&
  1493.        (fr = valid_time?(h, min, s))
  1494.       raise ArgumentError, 'invalid date'
  1495.     end
  1496.     if String === of
  1497.       of = Rational(zone_to_diff(of) || 0, 86400)
  1498.     end
  1499.     new!(jd_to_ajd(jd, fr, of), of, sg)
  1500.   end
  1501.  
  1502.   # Create a new DateTime object corresponding to the specified
  1503.   # Civil Date and hour +h+, minute +min+, second +s+.
  1504.   #
  1505.   # The 24-hour clock is used.  Negative values of +h+, +min+, and
  1506.   # +sec+ are treating as counting backwards from the end of the
  1507.   # next larger unit (e.g. a +min+ of -2 is treated as 58).  No
  1508.   # wraparound is performed.  If an invalid time portion is specified,
  1509.   # an ArgumentError is raised.
  1510.   #
  1511.   # +of+ is the offset from UTC as a fraction of a day (defaults to 0).
  1512.   # +sg+ specifies the Day of Calendar Reform.
  1513.   #
  1514.   # +y+ defaults to -4712, +m+ to 1, and +d+ to 1; this is Julian Day
  1515.   # Number day 0.  The time values default to 0.
  1516.   def self.civil(y=-4712, m=1, d=1, h=0, min=0, s=0, of=0, sg=ITALY)
  1517.     unless (jd = valid_civil?(y, m, d, sg)) &&
  1518.        (fr = valid_time?(h, min, s))
  1519.       raise ArgumentError, 'invalid date'
  1520.     end
  1521.     if String === of
  1522.       of = Rational(zone_to_diff(of) || 0, 86400)
  1523.     end
  1524.     new!(jd_to_ajd(jd, fr, of), of, sg)
  1525.   end
  1526.  
  1527.   class << self; alias_method :new, :civil end
  1528.  
  1529.   # Create a new DateTime object corresponding to the specified
  1530.   # Commercial Date and hour +h+, minute +min+, second +s+.
  1531.   #
  1532.   # The 24-hour clock is used.  Negative values of +h+, +min+, and
  1533.   # +sec+ are treating as counting backwards from the end of the
  1534.   # next larger unit (e.g. a +min+ of -2 is treated as 58).  No
  1535.   # wraparound is performed.  If an invalid time portion is specified,
  1536.   # an ArgumentError is raised.
  1537.   #
  1538.   # +of+ is the offset from UTC as a fraction of a day (defaults to 0).
  1539.   # +sg+ specifies the Day of Calendar Reform.
  1540.   #
  1541.   # +y+ defaults to 1582, +w+ to 41, and +d+ to 5; this is the Day of
  1542.   # Calendar Reform for Italy and the Catholic countries.
  1543.   # The time values default to 0.
  1544.   def self.commercial(y=1582, w=41, d=5, h=0, min=0, s=0, of=0, sg=ITALY)
  1545.     unless (jd = valid_commercial?(y, w, d, sg)) &&
  1546.        (fr = valid_time?(h, min, s))
  1547.       raise ArgumentError, 'invalid date'
  1548.     end
  1549.     if String === of
  1550.       of = Rational(zone_to_diff(of) || 0, 86400)
  1551.     end
  1552.     new!(jd_to_ajd(jd, fr, of), of, sg)
  1553.   end
  1554.  
  1555.   def self.weeknum(y=1582, w=41, d=5, f=0, h=0, min=0, s=0, of=0, sg=ITALY) # :nodoc:
  1556.     unless (jd = valid_weeknum?(y, w, d, f, sg)) &&
  1557.        (fr = valid_time?(h, min, s))
  1558.       raise ArgumentError, 'invalid date'
  1559.     end
  1560.     if String === of
  1561.       of = Rational(zone_to_diff(of) || 0, 86400)
  1562.     end
  1563.     new!(jd_to_ajd(jd, fr, of), of, sg)
  1564.   end
  1565.  
  1566.   private_class_method :weeknum
  1567.  
  1568.   def self.new_by_frags(elem, sg) # :nodoc:
  1569.     elem = rewrite_frags(elem)
  1570.     elem = complete_frags(elem)
  1571.     unless (jd = valid_date_frags?(elem, sg)) &&
  1572.        (fr = valid_time_frags?(elem))
  1573.       raise ArgumentError, 'invalid date'
  1574.     end
  1575.     fr += (elem[:sec_fraction] || 0) / 86400
  1576.     of = Rational(elem[:offset] || 0, 86400)
  1577.     new!(jd_to_ajd(jd, fr, of), of, sg)
  1578.   end
  1579.  
  1580.   private_class_method :new_by_frags
  1581.  
  1582.   # Create a new DateTime object by parsing from a String
  1583.   # according to a specified format.
  1584.   #
  1585.   # +str+ is a String holding a date-time representation.
  1586.   # +fmt+ is the format that the date-time is in.  See
  1587.   # date/format.rb for details on supported formats.
  1588.   #
  1589.   # The default +str+ is '-4712-01-01T00:00:00+00:00', and the default
  1590.   # +fmt+ is '%FT%T%z'.  This gives midnight on Julian Day Number day 0.
  1591.   #
  1592.   # +sg+ specifies the Day of Calendar Reform.
  1593.   #
  1594.   # An ArgumentError will be raised if +str+ cannot be
  1595.   # parsed.
  1596.   def self.strptime(str='-4712-01-01T00:00:00+00:00', fmt='%FT%T%z', sg=ITALY)
  1597.     elem = _strptime(str, fmt)
  1598.     new_by_frags(elem, sg)
  1599.   end
  1600.  
  1601.   # Create a new DateTime object by parsing from a String,
  1602.   # without specifying the format.
  1603.   #
  1604.   # +str+ is a String holding a date-time representation.
  1605.   # +comp+ specifies whether to interpret 2-digit years
  1606.   # as 19XX (>= 69) or 20XX (< 69); the default is not to.
  1607.   # The method will attempt to parse a date-time from the String
  1608.   # using various heuristics; see #_parse in date/format.rb
  1609.   # for more details.  If parsing fails, an ArgumentError
  1610.   # will be raised.
  1611.   #
  1612.   # The default +str+ is '-4712-01-01T00:00:00+00:00'; this is Julian
  1613.   # Day Number day 0.
  1614.   #
  1615.   # +sg+ specifies the Day of Calendar Reform.
  1616.   def self.parse(str='-4712-01-01T00:00:00+00:00', comp=false, sg=ITALY)
  1617.     elem = _parse(str, comp)
  1618.     new_by_frags(elem, sg)
  1619.   end
  1620.  
  1621.   public :hour, :min, :sec, :sec_fraction, :zone, :offset, :new_offset
  1622. #     :minute, :second, :second_fraction
  1623.  
  1624.   def to_s # 4p
  1625.     format('%.4d-%02d-%02dT%02d:%02d:%02d%s',
  1626.        year, mon, mday, hour, min, sec, zone)
  1627.   end
  1628.  
  1629. end
  1630.  
  1631. class Time
  1632.  
  1633. #  def to_time() getlocal end
  1634.  
  1635.   def to_date
  1636.     jd = Date.civil_to_jd(year, mon, mday, Date::ITALY)
  1637.     Date.new!(Date.jd_to_ajd(jd, 0, 0), 0, Date::ITALY)
  1638.   end
  1639.  
  1640.   def to_datetime
  1641.     jd = DateTime.civil_to_jd(year, mon, mday, DateTime::ITALY)
  1642.     fr = DateTime.time_to_day_fraction(hour, min, [sec, 59].min) +
  1643.       Rational(usec, 86400_000_000)
  1644.     of = Rational(utc_offset, 86400)
  1645.     DateTime.new!(DateTime.jd_to_ajd(jd, fr, of), of, DateTime::ITALY)
  1646.   end
  1647.  
  1648.   private :to_date, :to_datetime
  1649.  
  1650. end
  1651.  
  1652. class Date
  1653.  
  1654. =begin
  1655.   def to_time() Time.local(year, mon, mday) end
  1656.   def to_date() self end
  1657.   def to_datetime() DateTime.new!(self.class.jd_to_ajd(jd, 0, 0), @of, @sg) end
  1658. =end
  1659.  
  1660.   # Create a new Date object representing today.
  1661.   #
  1662.   # +sg+ specifies the Day of Calendar Reform.
  1663.   def self.today(sg=ITALY) Time.now.__send__(:to_date)    .new_start(sg) end
  1664.  
  1665.   # Create a new DateTime object representing the current time.
  1666.   #
  1667.   # +sg+ specifies the Day of Calendar Reform.
  1668.   def self.now  (sg=ITALY) Time.now.__send__(:to_datetime).new_start(sg) end
  1669.  
  1670.   private_class_method :now
  1671.  
  1672. end
  1673.  
  1674. class DateTime < Date
  1675.  
  1676. =begin
  1677.   def to_time
  1678.     d = new_offset(0)
  1679.     d.instance_eval do
  1680.       Time.utc(year, mon, mday, hour, min, sec,
  1681.            (sec_fraction * 86400000000).to_i)
  1682.     end.
  1683.     getlocal
  1684.   end
  1685.  
  1686.   def to_date() Date.new!(self.class.jd_to_ajd(jd, 0, 0), 0, @sg) end
  1687.   def to_datetime() self end
  1688. =end
  1689.  
  1690.   private_class_method :today
  1691.   public_class_method  :now
  1692.  
  1693. end
  1694.  
  1695. class Date
  1696.  
  1697.   class << self
  1698.  
  1699.     def deprecated_class_method_alias(old, new) # :nodoc:
  1700.       module_eval <<-"end;"
  1701.     class << self
  1702.       def #{old}(*args, &block)
  1703.         if $VERBOSE
  1704.           warn("\#{caller.shift.sub(/:in .*/, '')}: " \
  1705.            "warning: \#{self}::#{old} is deprecated; " \
  1706.            "use \#{self}::#{new}")
  1707.         end
  1708.         #{new}(*args, &block)
  1709.       end
  1710.     end
  1711.       end;
  1712.     end
  1713.  
  1714.     private :deprecated_class_method_alias
  1715.  
  1716.     def deprecated_alias(old, new) # :nodoc:
  1717.       module_eval <<-"end;"
  1718.     def #{old}(*args, &block)
  1719.       if $VERBOSE
  1720.         warn("\#{caller.shift.sub(/:in .*/, '')}: " \
  1721.          "warning: \#{self.class}\##{old} is deprecated; " \
  1722.          "use \#{self.class}\##{new}")
  1723.       end
  1724.       #{new}(*args, &block)
  1725.     end
  1726.       end;
  1727.     end
  1728.  
  1729.     private :deprecated_alias
  1730.  
  1731.   end
  1732.  
  1733.   [ %w(os?    julian?),
  1734.     %w(ns?    gregorian?),
  1735.     %w(exist1?    valid_jd?),
  1736.     %w(exist2?    valid_ordinal?),
  1737.     %w(exist3?    valid_date?),
  1738.     %w(exist?    valid_date?),
  1739.     %w(existw?    valid_commercial?),
  1740.     %w(new0    new!),
  1741.     %w(new1    jd),
  1742.     %w(new2    ordinal),
  1743.     %w(new3    new),
  1744.     %w(neww    commercial)
  1745.   ].each do |old, new|
  1746.     deprecated_class_method_alias(old, new)
  1747.   end
  1748.  
  1749.   [ %w(os?    julian?),
  1750.     %w(ns?    gregorian?),
  1751.     %w(sg    start),
  1752.     %w(newsg    new_start),
  1753.     %w(of    offset),
  1754.     %w(newof    new_offset)
  1755.   ].each do |old, new|
  1756.     deprecated_alias(old, new)
  1757.   end
  1758.  
  1759.   private :of, :newof
  1760.  
  1761. end
  1762.  
  1763. class DateTime < Date
  1764.  
  1765.   public :of, :newof
  1766.  
  1767. end
  1768.